// 
//  Copyright (C) 2009 Jacek Trubłajewicz
// 
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//  
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 

using System;
using System.Text;
using System.IO;
using System.Security.AccessControl;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
using Mono.Unix;
using NLog;

namespace wxGadu
{
	/// <summary>
	/// 
	/// </summary>
	public delegate void UserConfigChangedEventHandler(object sender);
	
	/// <summary>
	/// Keeps basic application configuration data.
	/// Implements functionality to read and write <c>UserConfig</c> and
	/// updating controls parameters when user change config settings.
	/// </summary>
	public class AppConfig
	{
		/// <summary>
		/// Application name
		/// </summary>
		public static readonly string APP_NAME = "wxGadu";
		/// <summary>
		/// Name of a file in which contacts are stored
		/// </summary>
		public static readonly string CONTACTS_FILE_NAME = "contacts.xml";
		/// <summary>
		/// Name of a directory in which avatars are stored
		/// </summary>
		public static readonly string AVATARS_NAME = "avatars";
		/// <summary>
		/// Name of a file which keeps information about user profiles
		/// </summary>
		public static readonly string PROFILES_FILE_NAME = "profiles.xml";
		/// <summary>
		/// Name of a file which keeps user configuration
		/// </summary>
		public static readonly string USER_CONFIG_NAME = "config.xml";
		/// <summary>
		/// Name of a file which list of user descriptions
		/// </summary>
		public static readonly string DESCRIPTIONS_FILE_NAME = "descriptions.xml";
		/// <summary>
		/// Name of a file which keeps application log
		/// </summary>
		public static readonly string LOG_FILE_NAME = "wxGadu.log";
		/// <summary>
		/// Name of a directory in which history is stored
		/// </summary>
		public static readonly string HISTORY_NAME = "history";
		/// <summary>
		/// Name of a logging target for file logging
		/// </summary>
		public static readonly string FILE_LOG_TARGET_NAME = "file";
		/// <summary>
		/// Name of a logging target for console logging
		/// </summary>
		public static readonly string CONSOLE_LOG_TARGET_NAME = "console";
		private string appDir;
		private string userDir;
		private string contactsFile;
		private string avatarsDir;
		private string historyDir;
		private string configFile;
		private string descriptionsFile;
		private string logFile;
		private string password;
#if LOG
		private Logger logger = LogManager.GetCurrentClassLogger();
#endif
		private UserConfig userConf;
		public event UserConfigChangedEventHandler UserConfigChanged;
		
		public AppConfig(string profileName, string password)
		{
			this.password = password;
			
			#region initialize paths
			StringBuilder sb = new StringBuilder();
			sb.Append(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
			sb.Append(Path.DirectorySeparatorChar); 
			sb.Append(".");
			sb.Append(APP_NAME);
			appDir = sb.ToString();
			sb.Append(Path.DirectorySeparatorChar); 
			sb.Append(profileName);
			userDir = sb.ToString();
			
			contactsFile = userDir + Path.DirectorySeparatorChar + CONTACTS_FILE_NAME;
			avatarsDir = userDir + Path.DirectorySeparatorChar + AVATARS_NAME;
			configFile = userDir + Path.DirectorySeparatorChar + USER_CONFIG_NAME;	
			descriptionsFile = userDir + Path.DirectorySeparatorChar + DESCRIPTIONS_FILE_NAME;
			logFile = userDir + Path.DirectorySeparatorChar + LOG_FILE_NAME;
			historyDir = userDir + Path.DirectorySeparatorChar + HISTORY_NAME;
			#endregion
			
#if LOG
			logger.Trace(String.Format(
			              Catalog.GetString("Application configuration dir: {0} \nUser profil home dir: {1}\nUser contacts file: {2}\nUser avatars dir: {3}"), 
			              appDir,
			              userDir, 
			              contactsFile, 
			              avatarsDir));
#endif
			
			#region check paths 
			try
			{
				if (!Directory.Exists(appDir))
				{
#if LOG
					logger.Warn(Catalog.GetString("User home dir doesn't exist, creating..."));
#endif
					Directory.CreateDirectory(userDir);
				}
			}
			catch (Exception e)
			{
#if LOG
				logger.FatalException(Catalog.GetString("Unable to create application config directory"), e);
#endif
				throw;
			}
			
			
			try
			{
				if (!Directory.Exists(userDir))
				{
#if LOG
					logger.Warn(Catalog.GetString("User home dir doesn't exist, creating..."));
#endif
					Directory.CreateDirectory(userDir);
				}
			}
			catch (Exception e)
			{
#if LOG
				logger.FatalException(Catalog.GetString("Unable to create user home directory"), e);
#endif
				throw;
			}
			
//			DirectoryInfo uDi = new DirectoryInfo(userDir);
//			DirectorySecurity uDs = uDi.GetAccessControl();
			
			try
			{
				if (!Directory.Exists(avatarsDir))
				{
#if LOG
					logger.Warn(Catalog.GetString("Avatars directory doesn't exist, creating..."));
#endif
					Directory.CreateDirectory(avatarsDir);
				}
			}
			catch (Exception e)
			{
#if LOG
				logger.FatalException(Catalog.GetString("Unable to create avatars directory"), e);
#endif
				throw;
			}	
				
			#endregion
			
			try
			{
				LoadUserConfig();
			}
			catch 
			{
#if LOG
				logger.Error(string.Format(Catalog.GetString("Unable to load configuration file: {0}. Loading default settings..."), configFile));
#endif
				userConf = new UserConfig();
			}
			
//			SaveUserConfig();
//			UserConfig cfg = LoadUserConfig();
//			System.Console.WriteLine("uin" + cfg.Uin);
//				System.Console.WriteLine("position =="+ cfg.MainWindowPosition);
//			System.Console.WriteLine("status == " + cfg.DefaultStatus.ToString());
//			if (cfg.ContactListBackground == null)
//				System.Console.WriteLine("color = null" + cfg.ContactListBackground);
			
		}
		
		/// <summary>
		/// Loads user configuration stored in file
		/// </summary>
		/// <returns>
		/// A <see cref="UserConfig"/>
		/// object with user configuration settings
		/// </returns>
		public UserConfig LoadUserConfig()
		{
#if LOG
			logger.Trace(Catalog.GetString("Loading user (profile) configuration settings..."));
#endif
			FileStream fs = new FileStream(configFile, FileMode.Open, FileAccess.Read);
			UserConfig cfg;
			try
			{
				XmlSerializer ser = new XmlSerializer(typeof(UserConfig));
				cfg = (UserConfig) ser.Deserialize(fs);
			}
			finally
			{
				fs.Close();
			}
			
			userConf = cfg;
			return cfg;
		}
		
		/// <summary>
		/// Saves user configuration to file
		/// </summary>
		/// <param name="config">
		/// A <see cref="UserConfig"/>
		/// configuration object that should be saved
		/// </param>
		public void SaveUserConfig(UserConfig config)
		{
			// TODO: fs should be global and new object should be created inside try..catch
			FileStream fs = new FileStream(configFile, FileMode.Create, FileAccess.Write);
			try
			{
				XmlSerializer ser = new XmlSerializer(typeof(UserConfig));
				ser.Serialize(fs, config);
			}
			finally
			{
				fs.Close();
			}
#if LOG
			logger.Trace(Catalog.GetString("User configuration saved to file succesfuly"));
#endif 
		}
		
		/// <summary>
		/// Saves user configuration to file
		/// </summary>
		/// <remarks>
		/// Configuration data is
		/// stored in <c>AppConfig.userConf</c>
		/// </remarks>
		public void SaveUserConfig()
		{
			if (userConf is UserConfig)
				SaveUserConfig(userConf);
			else
			{
#if LOG
				logger.Error(Catalog.GetString("Atempt to write empty (null) user configuration object to file"));
#endif
			}
		}
		
		/// <summary>
		/// Launches event to inform subscribers about
		/// changes in user configuration
		/// </summary>
		public void ApplyUserSettings()
		{
			if (userConf is UserConfig)
				if (UserConfigChanged != null)
					UserConfigChanged(this);
		}
		
		//// <value>
		/// Path to main user configuration directory. 
		/// I.e. /home/user/.wxGadu/
		/// </value>
		public string AppDir
		{
			get { return appDir; }
		}
		
		//// <value>
		/// Path to profile configuration directory. 
		/// I.e. /home/user/.wxGadu/ProfileName
		/// </value>
		public string UserDir
		{
			get { return userDir; }
		}
			
		//// <value>
		/// Path to profile contacts file
		/// I.e. /home/user/.wxGadu/ProfileName/contacts.xml
		/// </value>
		public string ContactsFile
		{
			get { return contactsFile; }
		}
		
		//// <value>
		/// Path to profile config file
		/// I.e. /home/user/.wxGadu/ProfileName/config.xml
		/// </value>
		public string ConfigFile
		{
			get { return configFile; }
		}
		
		//// <value>
		/// Path to profile descriptions file
		/// I.e. /home/user/.wxGadu/ProfileName/descriptions.xml
		/// </value>
		public string DescriptionsFile
		{
			get { return descriptionsFile; }
		}
		
		//// <value>
		/// Path to profile contacts photo (avatars) directory
		/// I.e. /home/user/.wxGadu/ProfileName/contacts.xml
		/// </value>
		public string AvatarsDir
		{
			get { return avatarsDir; }
		}
		
		//// <value>
		/// Path to history directory. 
		/// I.e. /home/user/.wxGadu/ProfileName/history
		/// </value>
		public string HistoryDir
		{
			get { return historyDir; }
		}
		
		//// <value>
		/// User configuration object loaded from 
		/// file by <c>LoadUserConfig()</c> method.
		/// </value>
		public UserConfig UserConf
		{
			get { return userConf; }
			set { userConf = value; }
		}
		
		public string LogFile
		{
			get { return logFile; }
		}
		
		public string Password
		{
			get { return password; }
			set { password = value; }
		}
	}
}
